package base.transporte;

import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;

import base.GerenciadorConexoes;

public class SRSocket {

	private UDPSocketSR socket;
	private Receptor receptor;
	private Thread receptor_thread;
	private Emissor emissor;
	private Thread emissor_thread;
	@SuppressWarnings("unused")
	private String nome;
	boolean alive;
	
	private InetAddress remote_ip;
	private int remote_port;
	

	public SRSocket(InetAddress remote_ip, int remote_port, String nome) throws SocketException {
		this.remote_ip = remote_ip;
		this.remote_port = remote_port;
		
		socket = new UDPSocketSR();
		socket.setReceiveBufferSize((Constantes.dataMax + 8));
		socket.setSendBufferSize((Constantes.dataMax + 8) * Constantes.windowSize);
		
		receptor = new Receptor(this, nome);
		receptor_thread = (new Thread(receptor));
		receptor_thread.setPriority(8);
		receptor_thread.start();
		
		emissor = new Emissor(this, nome);
		emissor_thread = (new Thread(emissor));
		emissor_thread.start();
		
		this.nome = nome;
		this.alive = true;
		GerenciadorConexoes.getInstance().inserirSRSocket(this);

	}
	
	public SRSocket(UDPSocketSR socket, InetAddress remote_ip, int remote_port, String nome) throws SocketException {
		this.remote_ip = remote_ip;
		this.remote_port = remote_port;
		
		this.socket = socket;
		socket.setReceiveBufferSize((Constantes.dataMax + 8));
		socket.setSendBufferSize((Constantes.dataMax + 8) * Constantes.windowSize);
		
		receptor = new Receptor(this, nome);
		receptor_thread = (new Thread(receptor));
		receptor_thread.setPriority(8);
		receptor_thread.start();
		
		emissor = new Emissor(this, nome);
		emissor_thread = (new Thread(emissor));
		emissor_thread.start();
		
		this.nome = nome;
		this.alive = true;
		
		GerenciadorConexoes.getInstance().inserirSRSocket(this);

	}
	
	public InetAddress getRemoteIP(){
		return this.remote_ip;
	}

	public int getRemotePort(){
		return this.remote_port;
	}
	
	public void sendPacket(SRPacket pkt) throws IOException{
		socket.sendPacket(pkt, remote_ip, remote_port);
	}

	public SRPacket receivePacket() throws SocketTimeoutException, IOException{
		return socket.receivePacket();
	}
	
	public void sendAck(int seqNum) throws Exception{
		socket.sendAck(seqNum, remote_ip, remote_port);
	}
	
	public int getLocalPort() {
		return this.socket.getLocalPort();
	}

	public int getVelUploadBytes() {
		return this.emissor.getVelocimetro().getVelocidadeBytesPorSeg();
	}

	public int getVelDownloadBytes() {
		return this.receptor.getVelocimetro().getVelocidadeBytesPorSeg();
	}

	public String getVelUploadFormatada() {
		return this.emissor.getVelocimetro().getVelocidadeFormatada();
	}

	public String getVelDownloadFormatada() {
		return this.receptor.getVelocimetro().getVelocidadeFormatada();
	}

	public void enviarPacote(SRPacket pacote) {
		//System.out.println("Enviando pacote para: " + this.remote_ip);
		this.emissor.inserirPacote(pacote);
	}

	public SRPacket receberPacote() {
		//System.out.println("Recebendo pacote de: " + this.remote_ip);
		return this.receptor.getNextPacket();
	}

	public void inserirAckAEsperar(int seqNum, EnviaPacote thread) {
		this.receptor.inserirAckAEsperar(seqNum, thread);
	}

	public void desativar() {
		while (!emissor.isEmpty())
			;
		emissor.desligar();
		socket.close();
		receptor_thread.interrupt();
		emissor_thread.interrupt();
		alive = false;
		GerenciadorConexoes.getInstance().removerSRSocket(this);
	}
	
	public boolean isAlive() {
		return alive;
	}
}